package com.vchello.dao.shiro;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.vchello.bean.security.RoleSecurity;
import com.vchello.bean.security.UserRole;
import com.vchello.bean.user.User;
import com.vchello.dao.security.UserRoleDao;
import com.vchello.dao.user.UserDao;


/**
 * 
 * @author power
 * 
 */
@Service
public class HibernateShiroRealm extends AuthorizingRealm {
	
	@Autowired
	private UserDao userDao;
	@Autowired
	private UserRoleDao userRoleDao;

	/*
	 * (non-Javadoc)
	 * 授权操作，角色对应的权限
	 * @see
	 * org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache
	 * .shiro.subject.PrincipalCollection)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		// null usernames are invalid
		if (principals == null) {
			throw new AuthorizationException(
					"PrincipalCollection method argument cannot be null.");
		}

		String username = (String) getAvailablePrincipal(principals);
		try {

			User user = userDao.findUserByPhone(username);
			if(null == user) {
				return null;
			}
			//checkUser(user, username);

			Set<String> roleNames = new HashSet<String>();
			Set<String> permissions = new HashSet<String>();
			UserRole userRole = userRoleDao.findUserRole(user.getId());
			roleNames.add(userRole.getRole().getName());
			for (RoleSecurity roleSecurity : userRole.getRole().getRoleSecurityList()) {
				permissions.add(roleSecurity.getSecurity().getPermission());
			}
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
			info.setStringPermissions(permissions);
			return info;
		} catch (Exception e) {
			throw translateException(e);
		}
	}

	private void checkUser(User user, String username) {
		if (null == user) {
			throw new UnknownAccountException("No account found for user ["
					+ username + "]");
		}
		
		if (user.getStatus() == 2) {
            // 用户被锁定抛出异常
            throw new LockedAccountException();
        }
	}

	private AuthenticationException translateException(Exception e) {
		if (AuthenticationException.class.isAssignableFrom(e.getClass())) {
			return (AuthenticationException) e;
		}

		return new AuthenticationException(e);
	}

	/*
	 * (non-Javadoc)
	 * 认证操作，判断一个请求是否被允许进入系统 
	 * @see
	 * org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org
	 * .apache.shiro.authc.AuthenticationToken)
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		String username = upToken.getUsername();

		// Null username is invalid
		if (StringUtils.isBlank(username)) {
			throw new AccountException(
					"Null usernames are not allowed by this realm.");
		}
		try {

			User user = userDao.findUserByPhone(username);
//			checkUser(user, username);
			if(null == user) {
				return null;
			}
			String password = new String(upToken.getPassword());
            if (!password.equals(user.getPassword())) {
            	throw new AccountException(
    					"Null password are not allowed by this realm.");
            }
			return buildAuthenticationInfo(user.getPhone(), user
					.getPassword());
		} catch (Exception e) {
			e.printStackTrace();
			throw translateException(e);
		}
	}

	protected AuthenticationInfo buildAuthenticationInfo(String username,
			String password) {
		return new SimpleAuthenticationInfo(username, password, getName());
	}
}
